// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/lib/ui/dart_ui.h"

#include <mutex>
#include <string_view>

#include "flutter/common/constants.h"
#include "flutter/common/settings.h"
#include "flutter/fml/build_config.h"
#include "flutter/lib/ui/compositing/scene.h"
#include "flutter/lib/ui/compositing/scene_builder.h"
#include "flutter/lib/ui/dart_runtime_hooks.h"
#include "flutter/lib/ui/isolate_name_server/isolate_name_server_natives.h"
#include "flutter/lib/ui/painting/canvas.h"
#include "flutter/lib/ui/painting/codec.h"
#include "flutter/lib/ui/painting/color_filter.h"
#include "flutter/lib/ui/painting/engine_layer.h"
#include "flutter/lib/ui/painting/fragment_program.h"
#include "flutter/lib/ui/painting/fragment_shader.h"
#include "flutter/lib/ui/painting/gradient.h"
#include "flutter/lib/ui/painting/image.h"
#include "flutter/lib/ui/painting/image_descriptor.h"
#include "flutter/lib/ui/painting/image_filter.h"
#include "flutter/lib/ui/painting/image_shader.h"
#include "flutter/lib/ui/painting/immutable_buffer.h"
#include "flutter/lib/ui/painting/path.h"
#include "flutter/lib/ui/painting/path_measure.h"
#include "flutter/lib/ui/painting/picture.h"
#include "flutter/lib/ui/painting/picture_recorder.h"
#include "flutter/lib/ui/painting/vertices.h"
#include "flutter/lib/ui/semantics/semantics_update.h"
#include "flutter/lib/ui/semantics/semantics_update_builder.h"
#include "flutter/lib/ui/semantics/string_attribute.h"
#include "flutter/lib/ui/text/font_collection.h"
#include "flutter/lib/ui/text/paragraph.h"
#include "flutter/lib/ui/text/paragraph_builder.h"
#include "flutter/lib/ui/window/platform_configuration.h"
#include "flutter/lib/ui/window/platform_isolate.h"
#include "third_party/tonic/converter/dart_converter.h"
#include "third_party/tonic/dart_args.h"
#include "third_party/tonic/logging/dart_error.h"

#ifdef IMPELLER_ENABLE_3D
#include "flutter/lib/ui/painting/scene/scene_node.h"
#include "flutter/lib/ui/painting/scene/scene_shader.h"
#endif  // IMPELLER_ENABLE_3D

using tonic::ToDart;

namespace flutter {

typedef CanvasImage Image;
typedef CanvasPathMeasure PathMeasure;
typedef CanvasGradient Gradient;
typedef CanvasPath Path;

// List of native static functions used as @Native functions.
// Items are tuples of ('function_name', 'parameter_count'), where:
//   'function_name' is the fully qualified name of the native function.
//   'parameter_count' is the number of parameters the function has.
//
// These are used to:
// - Instantiate FfiDispatcher templates to automatically create FFI Native
//   bindings.
//   If the name does not match a native function, the template will fail to
//   instatiate, resulting in a compile time error.
// - Resolve the native function pointer associated with an @Native function.
//   If there is a mismatch between name or parameter count an @Native is
//   trying to resolve, an exception will be thrown.
#define FFI_FUNCTION_LIST(V)                                       \
  /* Constructors */                                               \
  V(Canvas::Create)                                                \
  V(ColorFilter::Create)                                           \
  V(FragmentProgram::Create)                                       \
  V(ReusableFragmentShader::Create)                                \
  V(Gradient::Create)                                              \
  V(ImageFilter::Create)                                           \
  V(ImageShader::Create)                                           \
  V(ParagraphBuilder::Create)                                      \
  V(PathMeasure::Create)                                           \
  V(Path::Create)                                                  \
  V(PictureRecorder::Create)                                       \
  V(SceneBuilder::Create)                                          \
  V(SemanticsUpdateBuilder::Create)                                \
  /* Other */                                                      \
  V(FontCollection::LoadFontFromList)                              \
  V(ImageDescriptor::initEncoded)                                  \
  V(ImmutableBuffer::init)                                         \
  V(ImmutableBuffer::initFromAsset)                                \
  V(ImmutableBuffer::initFromFile)                                 \
  V(ImageDescriptor::initRaw)                                      \
  V(IsolateNameServerNatives::LookupPortByName)                    \
  V(IsolateNameServerNatives::RegisterPortWithName)                \
  V(IsolateNameServerNatives::RemovePortNameMapping)               \
  V(NativeStringAttribute::initLocaleStringAttribute)              \
  V(NativeStringAttribute::initSpellOutStringAttribute)            \
  V(PlatformConfigurationNativeApi::DefaultRouteName)              \
  V(PlatformConfigurationNativeApi::ScheduleFrame)                 \
  V(PlatformConfigurationNativeApi::EndWarmUpFrame)                \
  V(PlatformConfigurationNativeApi::Render)                        \
  V(PlatformConfigurationNativeApi::UpdateSemantics)               \
  V(PlatformConfigurationNativeApi::SetNeedsReportTimings)         \
  V(PlatformConfigurationNativeApi::SetIsolateDebugName)           \
  V(PlatformConfigurationNativeApi::RequestDartPerformanceMode)    \
  V(PlatformConfigurationNativeApi::GetPersistentIsolateData)      \
  V(PlatformConfigurationNativeApi::ComputePlatformResolvedLocale) \
  V(PlatformConfigurationNativeApi::SendPlatformMessage)           \
  V(PlatformConfigurationNativeApi::RespondToPlatformMessage)      \
  V(PlatformConfigurationNativeApi::GetRootIsolateToken)           \
  V(PlatformConfigurationNativeApi::RegisterBackgroundIsolate)     \
  V(PlatformConfigurationNativeApi::SendPortPlatformMessage)       \
  V(PlatformConfigurationNativeApi::SendChannelUpdate)             \
  V(PlatformConfigurationNativeApi::GetScaledFontSize)             \
  V(PlatformIsolateNativeApi::IsRunningOnPlatformThread)           \
  V(PlatformIsolateNativeApi::Spawn)                               \
  V(DartRuntimeHooks::Logger_PrintDebugString)                     \
  V(DartRuntimeHooks::Logger_PrintString)                          \
  V(DartRuntimeHooks::ScheduleMicrotask)                           \
  V(DartRuntimeHooks::GetCallbackHandle)                           \
  V(DartRuntimeHooks::GetCallbackFromHandle)                       \
  V(DartPluginRegistrant_EnsureInitialized)                        \
  V(Vertices::init)

// List of native instance methods used as @Native functions.
// Items are tuples of ('class_name', 'method_name', 'parameter_count'), where:
//   'class_name' is the name of the class containing the method.
//   'method_name' is the name of the method.
//   'parameter_count' is the number of parameters the method has including the
//                     implicit `this` parameter.
//
// These are used to:
// - Instantiate FfiDispatcher templates to automatically create FFI Native
//   bindings.
//   If the name does not match a native function, the template will fail to
//   instatiate, resulting in a compile time error.
// - Resolve the native function pointer associated with an @Native function.
//   If there is a mismatch between names or parameter count an @Native is
//   trying to resolve, an exception will be thrown.
#define FFI_METHOD_LIST(V)                          \
  V(Canvas, clipPath)                               \
  V(Canvas, clipRect)                               \
  V(Canvas, clipRRect)                              \
  V(Canvas, drawArc)                                \
  V(Canvas, drawAtlas)                              \
  V(Canvas, drawCircle)                             \
  V(Canvas, drawColor)                              \
  V(Canvas, drawDRRect)                             \
  V(Canvas, drawImage)                              \
  V(Canvas, drawImageNine)                          \
  V(Canvas, drawImageRect)                          \
  V(Canvas, drawLine)                               \
  V(Canvas, drawOval)                               \
  V(Canvas, drawPaint)                              \
  V(Canvas, drawPath)                               \
  V(Canvas, drawPicture)                            \
  V(Canvas, drawPoints)                             \
  V(Canvas, drawRRect)                              \
  V(Canvas, drawRect)                               \
  V(Canvas, drawShadow)                             \
  V(Canvas, drawVertices)                           \
  V(Canvas, getDestinationClipBounds)               \
  V(Canvas, getLocalClipBounds)                     \
  V(Canvas, getSaveCount)                           \
  V(Canvas, getTransform)                           \
  V(Canvas, restore)                                \
  V(Canvas, restoreToCount)                         \
  V(Canvas, rotate)                                 \
  V(Canvas, save)                                   \
  V(Canvas, saveLayer)                              \
  V(Canvas, saveLayerWithoutBounds)                 \
  V(Canvas, scale)                                  \
  V(Canvas, skew)                                   \
  V(Canvas, transform)                              \
  V(Canvas, translate)                              \
  V(Codec, dispose)                                 \
  V(Codec, frameCount)                              \
  V(Codec, getNextFrame)                            \
  V(Codec, repetitionCount)                         \
  V(ColorFilter, initLinearToSrgbGamma)             \
  V(ColorFilter, initMatrix)                        \
  V(ColorFilter, initMode)                          \
  V(ColorFilter, initSrgbToLinearGamma)             \
  V(EngineLayer, dispose)                           \
  V(FragmentProgram, initFromAsset)                 \
  V(ReusableFragmentShader, Dispose)                \
  V(ReusableFragmentShader, SetImageSampler)        \
  V(ReusableFragmentShader, ValidateSamplers)       \
  V(Gradient, initLinear)                           \
  V(Gradient, initRadial)                           \
  V(Gradient, initSweep)                            \
  V(Gradient, initTwoPointConical)                  \
  V(Image, dispose)                                 \
  V(Image, width)                                   \
  V(Image, height)                                  \
  V(Image, toByteData)                              \
  V(Image, colorSpace)                              \
  V(ImageDescriptor, bytesPerPixel)                 \
  V(ImageDescriptor, dispose)                       \
  V(ImageDescriptor, height)                        \
  V(ImageDescriptor, instantiateCodec)              \
  V(ImageDescriptor, width)                         \
  V(ImageFilter, initBlur)                          \
  V(ImageFilter, initDilate)                        \
  V(ImageFilter, initErode)                         \
  V(ImageFilter, initColorFilter)                   \
  V(ImageFilter, initComposeFilter)                 \
  V(ImageFilter, initMatrix)                        \
  V(ImageShader, dispose)                           \
  V(ImageShader, initWithImage)                     \
  V(ImmutableBuffer, dispose)                       \
  V(ImmutableBuffer, length)                        \
  V(ParagraphBuilder, addPlaceholder)               \
  V(ParagraphBuilder, addText)                      \
  V(ParagraphBuilder, build)                        \
  V(ParagraphBuilder, pop)                          \
  V(ParagraphBuilder, pushStyle)                    \
  V(Paragraph, alphabeticBaseline)                  \
  V(Paragraph, computeLineMetrics)                  \
  V(Paragraph, didExceedMaxLines)                   \
  V(Paragraph, dispose)                             \
  V(Paragraph, getClosestGlyphInfo)                 \
  V(Paragraph, getGlyphInfoAt)                      \
  V(Paragraph, getLineBoundary)                     \
  V(Paragraph, getLineMetricsAt)                    \
  V(Paragraph, getLineNumberAt)                     \
  V(Paragraph, getNumberOfLines)                    \
  V(Paragraph, getPositionForOffset)                \
  V(Paragraph, getRectsForPlaceholders)             \
  V(Paragraph, getRectsForRange)                    \
  V(Paragraph, getWordBoundary)                     \
  V(Paragraph, height)                              \
  V(Paragraph, ideographicBaseline)                 \
  V(Paragraph, layout)                              \
  V(Paragraph, longestLine)                         \
  V(Paragraph, maxIntrinsicWidth)                   \
  V(Paragraph, minIntrinsicWidth)                   \
  V(Paragraph, paint)                               \
  V(Paragraph, width)                               \
  V(PathMeasure, setPath)                           \
  V(PathMeasure, getLength)                         \
  V(PathMeasure, getPosTan)                         \
  V(PathMeasure, getSegment)                        \
  V(PathMeasure, isClosed)                          \
  V(PathMeasure, nextContour)                       \
  V(Path, addArc)                                   \
  V(Path, addOval)                                  \
  V(Path, addPath)                                  \
  V(Path, addPathWithMatrix)                        \
  V(Path, addPolygon)                               \
  V(Path, addRRect)                                 \
  V(Path, addRect)                                  \
  V(Path, arcTo)                                    \
  V(Path, arcToPoint)                               \
  V(Path, clone)                                    \
  V(Path, close)                                    \
  V(Path, conicTo)                                  \
  V(Path, contains)                                 \
  V(Path, cubicTo)                                  \
  V(Path, extendWithPath)                           \
  V(Path, extendWithPathAndMatrix)                  \
  V(Path, getBounds)                                \
  V(Path, getFillType)                              \
  V(Path, lineTo)                                   \
  V(Path, moveTo)                                   \
  V(Path, op)                                       \
  V(Path, quadraticBezierTo)                        \
  V(Path, relativeArcToPoint)                       \
  V(Path, relativeConicTo)                          \
  V(Path, relativeCubicTo)                          \
  V(Path, relativeLineTo)                           \
  V(Path, relativeMoveTo)                           \
  V(Path, relativeQuadraticBezierTo)                \
  V(Path, reset)                                    \
  V(Path, setFillType)                              \
  V(Path, shift)                                    \
  V(Path, transform)                                \
  V(PictureRecorder, endRecording)                  \
  V(Picture, GetAllocationSize)                     \
  V(Picture, dispose)                               \
  V(Picture, toImage)                               \
  V(Picture, toImageSync)                           \
  V(SceneBuilder, addPerformanceOverlay)            \
  V(SceneBuilder, addPicture)                       \
  V(SceneBuilder, addPlatformView)                  \
  V(SceneBuilder, addRetained)                      \
  V(SceneBuilder, addTexture)                       \
  V(SceneBuilder, build)                            \
  V(SceneBuilder, pop)                              \
  V(SceneBuilder, pushBackdropFilter)               \
  V(SceneBuilder, pushClipPath)                     \
  V(SceneBuilder, pushClipRRect)                    \
  V(SceneBuilder, pushClipRect)                     \
  V(SceneBuilder, pushColorFilter)                  \
  V(SceneBuilder, pushImageFilter)                  \
  V(SceneBuilder, pushOffset)                       \
  V(SceneBuilder, pushOpacity)                      \
  V(SceneBuilder, pushShaderMask)                   \
  V(SceneBuilder, pushTransformHandle)              \
  V(SceneBuilder, setCheckerboardOffscreenLayers)   \
  V(SceneBuilder, setCheckerboardRasterCacheImages) \
  V(SceneBuilder, setRasterizerTracingThreshold)    \
  V(Scene, dispose)                                 \
  V(Scene, toImage)                                 \
  V(Scene, toImageSync)                             \
  V(SemanticsUpdateBuilder, build)                  \
  V(SemanticsUpdateBuilder, updateCustomAction)     \
  V(SemanticsUpdateBuilder, updateNode)             \
  V(SemanticsUpdate, dispose)                       \
  V(Vertices, dispose)

#ifdef IMPELLER_ENABLE_3D

#define FFI_FUNCTION_LIST_3D(V) \
  V(SceneNode::Create)          \
  V(SceneShader::Create)

#define FFI_METHOD_LIST_3D(V)        \
  V(SceneNode, initFromAsset)        \
  V(SceneNode, initFromTransform)    \
  V(SceneNode, AddChild)             \
  V(SceneNode, SetTransform)         \
  V(SceneNode, SetAnimationState)    \
  V(SceneNode, SeekAnimation)        \
  V(SceneShader, SetCameraTransform) \
  V(SceneShader, Dispose)

#endif  // IMPELLER_ENABLE_3D

#define FFI_FUNCTION_INSERT(FUNCTION)           \
  g_function_dispatchers.insert(std::make_pair( \
      std::string_view(#FUNCTION),              \
      reinterpret_cast<void*>(                  \
          tonic::FfiDispatcher<void, decltype(&FUNCTION), &FUNCTION>::Call)));

#define FFI_METHOD_INSERT(CLASS, METHOD)                                       \
  g_function_dispatchers.insert(                                               \
      std::make_pair(std::string_view(#CLASS "::" #METHOD),                    \
                     reinterpret_cast<void*>(                                  \
                         tonic::FfiDispatcher<CLASS, decltype(&CLASS::METHOD), \
                                              &CLASS::METHOD>::Call)));

namespace {

std::once_flag g_dispatchers_init_flag;
std::unordered_map<std::string_view, void*> g_function_dispatchers;

void* ResolveFfiNativeFunction(const char* name, uintptr_t args) {
  auto it = g_function_dispatchers.find(name);
  return (it != g_function_dispatchers.end()) ? it->second : nullptr;
}

void InitDispatcherMap() {
  FFI_FUNCTION_LIST(FFI_FUNCTION_INSERT)
  FFI_METHOD_LIST(FFI_METHOD_INSERT)

#ifdef IMPELLER_ENABLE_3D
  FFI_FUNCTION_LIST_3D(FFI_FUNCTION_INSERT)
  FFI_METHOD_LIST_3D(FFI_METHOD_INSERT)
#endif  // IMPELLER_ENABLE_3D
}

}  // anonymous namespace

void DartUI::InitForIsolate(const Settings& settings) {
  std::call_once(g_dispatchers_init_flag, InitDispatcherMap);

  auto dart_ui = Dart_LookupLibrary(ToDart("dart:ui"));
  if (Dart_IsError(dart_ui)) {
    Dart_PropagateError(dart_ui);
  }

  // Set up FFI Native resolver for dart:ui.
  Dart_Handle result =
      Dart_SetFfiNativeResolver(dart_ui, ResolveFfiNativeFunction);
  if (Dart_IsError(result)) {
    Dart_PropagateError(result);
  }

  if (settings.enable_impeller) {
    result = Dart_SetField(dart_ui, ToDart("_impellerEnabled"), Dart_True());
    if (Dart_IsError(result)) {
      Dart_PropagateError(result);
    }
  }

  result = Dart_SetField(dart_ui, ToDart("_implicitViewId"),
                         Dart_NewInteger(kFlutterImplicitViewId));
  if (Dart_IsError(result)) {
    Dart_PropagateError(result);
  }
}

}  // namespace flutter
